package com.self.console.service.system;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;

import com.self.console.constant.enums.SystemConfigKey;
import com.self.console.dto.AdminDto;
import com.self.console.persistence.mapper.AdminMapper;
import com.self.console.persistence.mapper.SysConfigMapper;
import com.self.console.persistence.model.Admin;
import com.self.console.persistence.model.SysConfig;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.AbstractContextMapper;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.sangame.sow.enums.Flag;
import com.sangame.sow.ssh.orm.hibernate.support.Page;
import com.sangame.sow.ssh.service.result.DefaultResult;
import com.sangame.sow.ssh.service.result.Result;
import com.sangame.sow.ssh.service.result.ResultCode;
import com.sangame.sow.utils.GoogleAuthenticator;

@Service
public class AdminService {

	//	@Autowired
//	private LdapTemplate ldapTemplate;
	@Autowired
	private AdminMapper adminMapper;
	@Autowired
	private SysConfigMapper sysConfigMapper;

	public Page<Admin> findPage(Admin search) {
		Page<Admin> result = new Page<Admin>();
		result.setPageNo(search.getCurrentPage());
		result.setPageSize(search.getPageSize());
		List<Admin> data = adminMapper.findPage(search);

		long totalCount = adminMapper.countPage(search);
		result.setResult(data);
		result.setTotalCount(totalCount);
		return result;
	}

	/**
	 * 根据用户名查找用户
	 *
	 * @param userName
	 * @return
	 */
	public Admin checkLoginName(String username) {
		return adminMapper.findByUsername(username);
	}

	/**
	 *
	 * @param adminDto
	 * @return
	 */
	@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class, isolation=Isolation.DEFAULT)
	public Result login(final AdminDto adminDto, String authCode, String ip) {
		Result result = null;
		Admin user = adminMapper.findByUsername(adminDto.getRealName());
		if (user == null) {
			return new DefaultResult(new ResultCode(ResultCode.FAILURE, "登录失败，用户名不存在"));
		}
		if (Flag.TRUE.getValue().equals(user.getDisableFlag())) {
			return new DefaultResult(new ResultCode(ResultCode.FAILURE, "登录失败，该用户被禁用"));
		}

		int maxFailNum = 3; // 放在系统配置
		SysConfig config = sysConfigMapper.findByKey(SystemConfigKey.MAX_LOGIN_COUNT.getValue());
		if(config != null){
			maxFailNum = Integer.parseInt(config.getConfigValue());
		}
		// 验证图片验证码
		if (user.getFailNumber() > maxFailNum && !authCode.equals(adminDto.getAuthCode())) {// 验证码错误
			user.setFailNumber(user.getFailNumber() + 1L);
			adminMapper.update(user);

			result = new DefaultResult(new ResultCode(ResultCode.FAILURE, "验证码错误"));
			result.setModel("flag", false);
			return result;
		}

		AdminDto ldapDto = getUserByUid(adminDto.getRealName());
		if(ldapDto == null){
			return new DefaultResult(new ResultCode(ResultCode.FAILURE, "获取用户信息出错，请联系管理员"));
		}
		// 验证动态口令卡
		config = sysConfigMapper.findByKey(SystemConfigKey.CHECK_AUTH_CODE.getValue());
		if(config != null && "1".equals(config.getConfigValue())){
			if (!checkAuthCode(ldapDto.getAuthKey(), adminDto.getSnPassword())) {
				result = new DefaultResult(new ResultCode(ResultCode.FAILURE, "授权码错误"));
				if (user.getFailNumber() >= maxFailNum) {
					result.setModel("flag", false);
				} else {
					result.setModel("flag", true);
				}
				user.setFailNumber(user.getFailNumber() + 1L);
				adminMapper.update(user);
				return result;
			}
		}
		// 验证密码
		if (!authenticate(adminDto.getRealName(), adminDto.getUserPwd())) {
			result = new DefaultResult(new ResultCode(ResultCode.FAILURE, "验用户名或密码错误"));
			if (user.getFailNumber() >= maxFailNum) {
				result.setModel("flag", false);
			} else {
				result.setModel("flag", true);
			}

			user.setFailNumber(user.getFailNumber() + 1L);
			adminMapper.update(user);
			return result;
		}

		ldapDto.setLoginIp(ip);
		loadLoginInfo(user, ldapDto);

		user.setLastLoginTime(new Date());
		user.setLastLoginIp(ip);
		user.setFailNumber(0L);
		adminMapper.update(user);

		result = new DefaultResult(new ResultCode(ResultCode.SUCCESS, "登录成功，正在加载数据..."));
		result.setDefaultModel(ldapDto);
		result.setModel("flag", true);
		return result;
	}

	/**
	 * 根据uid取得用户信息
	 *
	 * @param uid
	 * @return
	 */
	public AdminDto getUserByUid(String loginName) {
		AndFilter andFilter = new AndFilter();
		andFilter.and(new EqualsFilter("uid", loginName));
		andFilter.and(new EqualsFilter("accountStatus", "active"));
		List<?> list = null;/*ldapTemplate.search("", andFilter.encode(), new AttributesMapper() {
			@Override
			public Object mapFromAttributes(Attributes attrs) throws NamingException {
				AdminDto admin = new AdminDto();
				admin.setName(attrs.get("uid").get().toString());
				admin.setRealName(attrs.get("cn").get().toString());
				admin.setEmail(attrs.get("mail").get().toString());
				if(attrs.get("sgAuth") != null && attrs.get("sgAuth").get() != null){
					admin.setAuthKey(attrs.get("sgAuth").get().toString());
				}
				return admin;
			}
		});*/
		if (list != null && !list.isEmpty()) {
			return (AdminDto) list.get(0);
		}
		return null;
	}

	/**
	 * 根据用户名和密码验证
	 *
	 * @param userDn
	 * @param credentials
	 * @return
	 */
	public boolean authenticate(String loginName, String credentials) {
		AndFilter andFilter = new AndFilter();
		andFilter.and(new EqualsFilter("uid", loginName));
		andFilter.and(new EqualsFilter("accountStatus", "active"));
		List<?> result =null;/* ldapTemplate.search(DistinguishedName.EMPTY_PATH, andFilter.encode(), new AbstractContextMapper() {
			protected Object doMapFromContext(DirContextOperations ctx) {
				return ctx.getNameInNamespace();
			}
		});*/
		if (result.size() != 1)
			return false;
		String userDn = (String) result.get(0);
		DirContext ctx = null;
		try {
			ctx = null;//ldapTemplate.getContextSource().getContext(userDn, credentials);
			return true;
		} catch (Exception e) {
			return false;
		} finally {
			if (ctx != null)
				LdapUtils.closeContext(ctx);
		}
	}

	/**
	 * 取管理员邮件列表，roleFlag=-1的用户为是管理员
	 *
	 * @return "" or mail[,mail]
	 */
	public String getRecipients() {
		StringBuilder sb = new StringBuilder();
		List<Admin> admins = adminMapper.findByRole(1L);

		for (Admin admin : admins) {
			AdminDto adminDto = getUserByUid(admin.getUserName());
			sb.append(adminDto.getEmail()).append(",");
		}

		return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1);
	}

	/**
	 *
	 * @return
	 */
	public List<Admin> findAll() {
		return adminMapper.findAll();
	}

	/**
	 * 查询用户
	 *
	 * @param id
	 * @return
	 */
	public Admin find(Long id) {
		Admin userInfo = adminMapper.find(id);
		return userInfo;
	}

	/**
	 * 删除用户
	 *
	 * @param id
	 */
	@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class, isolation=Isolation.DEFAULT)
	public Result destory(String ids) {
		if (StringUtils.isBlank(ids)) {
			return new DefaultResult(new ResultCode(ResultCode.FAILURE, "没有选择要删除的信息！"));
		}
		String[] grabUserInfoIDs = ids.split(",");
		for (String id : grabUserInfoIDs) {
			if (StringUtils.isNotBlank(id)) {
				Admin userInfo = find(Long.valueOf(id));
				if (userInfo != null) {
					adminMapper.delete(Long.valueOf(id));
				}
			}
		}
		return new DefaultResult(new ResultCode(ResultCode.SUCCESS, "删除成功！"));
	}

	private void loadLoginInfo(Admin userInfo, AdminDto adminDto) {
		adminDto.setId(userInfo.getId());
		adminDto.setLastLoginIp(userInfo.getLastLoginIp());
		adminDto.setLastLoginTime(userInfo.getLastLoginTime());
		adminDto.setLoginTime(new Date());
		adminDto.setRoleId(userInfo.getRoleId());

		Set<String> operCodeSet = userInfo.loadOperCode();
		adminDto.setOperCodeSet(operCodeSet);

		Set<String> menuCodeSet = new HashSet<String>();
		addMenuCode(operCodeSet, menuCodeSet);
		adminDto.setMenuCodeSet(menuCodeSet);
	}

	private void addMenuCode(Set<String> operCodeSet, Set<String> menuCodeSet) {
		Set<String> codeSet = menuCodeSet;
		for (String code : operCodeSet) {
			// 上级菜单显示
			String[] codes = code.split("_");
			String codeLevel = "";
			for (int i = 0; i < codes.length - 1; i++) {
				if (codeLevel.equals(""))
					codeLevel += codes[i];
				else
					codeLevel += "_" + codes[i];

				codeSet.add(codeLevel);
			}
			// 操作按钮显示
			codeSet.add(code);
		}
	}

	/**
	 * 谷歌认证
	 * @param admin
	 * @param authCode
	 * @return
	 */
	private boolean checkAuthCode(String secret, Long authCode) {
		if(authCode != null && StringUtils.isNotBlank(secret)) {
			// 获取授权码
			GoogleAuthenticator ga = new GoogleAuthenticator();
			ga.setWindowSize(1); //should give 5 * 30 seconds of grace...
			return ga.check_code(secret, authCode, System.currentTimeMillis());
		}
		return false;
	}

}